package com.pug.security.config.security;

import com.pug.security.config.security.handler.MyAccessDeniedHandler;
import com.pug.security.config.security.handler.MyLoginFailHandler;
import com.pug.security.config.security.handler.MyLoginSuccessHandler;
import com.pug.security.config.security.handler.MyLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Autowired
    private MyLoginSuccessHandler myLoginSuccessHandler;

    @Autowired
    private MyLoginFailHandler myLoginFailHandler;

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    @Qualifier("loginUserServiceImpl")
    private UserDetailsService userDetailsService;

    // 认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 基于接口的认证方式
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    // 授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 所有的请求开始接受认证
                .authorizeRequests()
                // 匹配到这些路径是不需要认证的
                .antMatchers("/toLogin", "/fail", "/nopermission").permitAll()

                // 配置权限 (建议路由规范：在这里统一管理)
//                .antMatchers("/user/list").hasRole("Admin")
//                .antMatchers("/user/search").hasRole("User")
//                .antMatchers("/user/get/**").hasAnyRole("Admin","User")

                // 匹配不到的，剩下的，全部进行认证
                .anyRequest().authenticated()
                // 下一个配置
                .and()
                // 提交表单
                .formLogin()
                // 给form表单的action进行赋值，默认是/login
                .loginPage("/toLogin")
                .loginProcessingUrl("/login")
                // 给form表单的input输入框的name赋值
                .usernameParameter("username")
                .passwordParameter("password")
                // 登陆成功处理器
                .successHandler(myLoginSuccessHandler)
                // 登陆失败处理器
                .failureHandler(myLoginFailHandler)
                // 设置记住密码
                .and()
                .rememberMe()
                .rememberMeParameter("remember-me")
                .rememberMeCookieName("ksd-remember-me")
                .tokenValiditySeconds(1800)
                .and()
                // 退出登录
                .logout()
                // 退出成功处理器
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .deleteCookies("ksd-remember-me", "JSESSIONID")
                .and()
                // 无权限403处理器
                .exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler)
                .and()
                // 关闭csrf跨站访问的防护
                .csrf().disable();


    }


    // 放行配置
    // 写在这里的资源放行是不会进入到过滤器链的。
    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity.ignoring().antMatchers(
                "/js/**", "/css/**", "/fonts/**", "/images/**", "/img/**");
    }


    // 注册一个加密器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


}
